/**
 * Plotar uma superfície com matplotpp. 
 */
#include <unistd.h>
#include <iostream>
#include "matplotpp.h"
#include <vector>
#include <cmath>

using namespace std;

class MP : public MatPlot {
private:
    vector<double> x;
    vector<double> y;
    dmat Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9, Z10, Z11, Z12, Z13, Z14, Z15;
    double X[6];

public:

    MP() {
        int n = 50;
        x = linspace(0, 1, n);
        y = linspace(0, 1, n);
        Z1 = dmat(n, vector<double>(n));
        Z2 = dmat(n, vector<double>(n));
        Z3 = dmat(n, vector<double>(n));
        Z4 = dmat(n, vector<double>(n));
        Z5 = dmat(n, vector<double>(n));
        Z6 = dmat(n, vector<double>(n));
        Z7 = dmat(n, vector<double>(n));
        Z8 = dmat(n, vector<double>(n));
        Z9 = dmat(n, vector<double>(n));
        Z10 = dmat(n, vector<double>(n));
        Z11 = dmat(n, vector<double>(n));
        Z12 = dmat(n, vector<double>(n));
        Z13 = dmat(n, vector<double>(n));
        Z14 = dmat(n, vector<double>(n));
        Z15 = dmat(n, vector<double>(n));

        //Z1 = x1 e x2 (x1 e x2 percorrem o domínio. O resto (x3..x6) fica fixo na raiz.)
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[0] = x[j];
                X[1] = y[i];
                Z1[i][j] = hart6(X);
            }



        //Z2 = x1 e x3
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[0] = x[j];
                X[2] = y[i];
                Z2[i][j] = hart6(X);
            }



        //Z3 = x1 e x4
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[0] = x[j];
                X[3] = y[i];
                Z3[i][j] = hart6(X);
            }



        //Z4 = x1 e x5
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[0] = x[j];
                X[4] = y[i];
                Z4[i][j] = hart6(X);
            }



        //Z5 = x1 e x6
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[0] = x[j];
                X[5] = y[i];
                Z5[i][j] = hart6(X);
            }



        //Z6 = x2 e x3
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[1] = x[j];
                X[2] = y[i];
                Z6[i][j] = hart6(X);
            }



        //Z7 = x2 e x4
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[1] = x[j];
                X[3] = y[i];
                Z7[i][j] = hart6(X);
            }



        //Z8 = x2 e x5
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[1] = x[j];
                X[4] = y[i];
                Z8[i][j] = hart6(X);
            }



        //Z9 = x2 e x6
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[1] = x[j];
                X[5] = y[i];
                Z9[i][j] = hart6(X);
            }



        //Z10 = x3 e x4
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[2] = x[j];
                X[3] = y[i];
                Z10[i][j] = hart6(X);
            }



        //Z11 = x3 e x5
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[2] = x[j];
                X[4] = y[i];
                Z11[i][j] = hart6(X);
            }



        //Z12 = x3 e x6
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[2] = x[j];
                X[5] = y[i];
                Z12[i][j] = hart6(X);
            }



        //Z13 = x4 e x5
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[3] = x[j];
                X[4] = y[i];
                Z13[i][j] = hart6(X);
            }



        //Z14 = x4 e x6
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[3] = x[j];
                X[5] = y[i];
                Z14[i][j] = hart6(X);
            }



        //Z15 = x5 e x6
        X[0] = 0.20169;
        X[1] = 0.150011;
        X[2] = 0.476874;
        X[3] = 0.275332;
        X[4] = 0.311652;
        X[5] = 0.657301;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                X[4] = x[j];
                X[5] = y[i];
                Z15[i][j] = hart6(X);
            }
    }

    double hart6(double X[]) { //X é um array com 6 doubles
        //0.20169 0.150011 0.476874 0.275332 0.311652 0.657301 -> ponto de mínimo global
        double c[4] = {1.0, 1.2, 3.0, 3.2};
        double a[4][6] = {10.0, 3.0, 17.0, 3.5, 1.7, 8.0, 0.05, 10.0, 17.0, 0.1, 8.0, 14.0, 3.0, 3.5, 1.7, 10.0, 17.0, 8.0, 17.0, 8.0, 0.05, 10.0, 0.1, 14.0};
        double p[4][6] = {0.1312, 0.1696, 0.5569, 0.0124, 0.8283, 0.5886, 0.2329, 0.4135, 0.8307, 0.3736, 0.1004, 0.9991, 0.2348, 0.1451, 0.3522, 0.2883, 0.3047, 0.665, 0.4047, 0.8828, 0.8732, 0.5743, 0.1091, 0.0381};

        double sum1 = 0;
        double sum2 = 0;

        for (int i = 0; i < 4; i++) {
            sum1 = 0;
            for (int j = 0; j < 6; j++)
                sum1 += a[i][j] * pow((X[j] - p[i][j]), 2);
            sum2 += c[i] * exp((-1) * sum1);
        }

        return -sum2;
    }

    void DISPLAY() {
        layer("variam x1 e x2", 1);
        mesh(x, y, Z1);
        colorbar();

        layer("variam x1 e x3", 0);
        surface(x, y, Z2);
        colorbar();

        layer("variam x1 e x4", 0);
        surface(x, y, Z3);
        colorbar();

        layer("variam x1 e x5", 0);
        surface(x, y, Z4);
        colorbar();

        layer("variam x1 e x6", 0);
        surface(x, y, Z5);
        colorbar();

        layer("variam x2 e x3", 0);
        surface(x, y, Z6);
        colorbar();

        layer("variam x2 e x4", 0);
        surface(x, y, Z7);
        colorbar();

        layer("variam x2 e x5", 0);
        surface(x, y, Z8);
        colorbar();

        layer("variam x2 e x6", 0);
        surface(x, y, Z9);
        colorbar();

        layer("variam x3 e x4", 0);
        surface(x, y, Z10);
        colorbar();

        layer("variam x3 e x5", 0);
        surface(x, y, Z11);
        colorbar();

        layer("variam x3 e x6", 0);
        surface(x, y, Z12);
        colorbar();

        layer("variam x4 e x5", 0);
        surface(x, y, Z13);
        colorbar();

        layer("variam x4 e x6", 0);
        surface(x, y, Z14);
        colorbar();

        layer("variam x5 e x6", 0);
        surface(x, y, Z15);
        colorbar();
    }
} mp;

void display() {
    mp.display();
}

void reshape(int w, int h) {
    mp.reshape(w, h);
}

void idle(void) {
    glutPostRedisplay();
    usleep(10000);
}

void motion(int x, int y) {
    mp.motion(x, y);
}

void mouse(int button, int state, int x, int y) {
    mp.mouse(button, state, x, y);
}

void passive(int x, int y) {
    mp.passivemotion(x, y);
}

void keyboard(unsigned char key, int x, int y) {
    mp.keyboard(key, x, y);
}

int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutCreateWindow(100, 100, 400, 300);
    glutDisplayFunc(display);
    glutSetWindowTitle("Teste do matplotpp");
    glutReshapeFunc(reshape);
    glutIdleFunc(idle);
    glutMotionFunc(motion);
    glutMouseFunc(mouse);
    glutPassiveMotionFunc(passive);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}
